package com.alex.wechat.component.handler;

import java.util.List;
import java.util.Map;

import org.jeecgframework.core.util.ResourceUtil;
import org.jeecgframework.web.system.pojo.base.TSDepart;
import org.jeecgframework.web.system.pojo.base.TSRole;
import org.jeecgframework.web.system.pojo.base.TSRoleUser;
import org.jeecgframework.web.system.pojo.base.TSUser;
import org.jeecgframework.web.system.pojo.base.TSUserOrg;
import org.jeecgframework.web.system.service.SystemService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.alex.wechat.app.account.entity.DeploymentMethod;
import com.alex.wechat.app.account.entity.WxAppAccountEntity;
import com.alex.wechat.app.account.service.WxAppAccountServiceI;
import com.alex.wechat.app.config.WxAppContext;
import com.alex.wechat.component.config.WxComponentContext;
import com.alex.wechat.core.handler.WxAccountType;
import com.alex.wechat.core.handler.WxHandler;
import com.alex.wechat.mp.account.entity.WxAccountEntity;
import com.alex.wechat.mp.account.service.WxAccountServiceI;
import com.alex.wechat.mp.config.WxConsts;
import com.gomore.jeecg.common.ServiceException;

import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.component.api.WxCompConfigStorage;
import me.chanjar.weixin.component.api.WxCompService;
import me.chanjar.weixin.component.bean.author.WxApiQueryAuthResult.WxAuthorizationInfo;
import me.chanjar.weixin.component.bean.author.WxAppDomains;
import me.chanjar.weixin.component.bean.author.WxGetAuthorizerInfoResult;
import me.chanjar.weixin.component.bean.author.WxGetAuthorizerInfoResult.WxAuthorizerInfo;
import me.chanjar.weixin.message.bean.WxXmlMessage;
import me.chanjar.weixin.message.rule.WxMessageHandler;

/**
 * 开放平台授权Handler
 * 
 * @author Debenson
 * @since 0.1
 */
@WxHandler(infoType = WxConsts.INFO_TYPE_AUTHORIZED, accountType = WxAccountType.COMPONENT)
public class AuthorizedHandler implements WxMessageHandler {
  private static final Logger logger = LoggerFactory.getLogger(AuthorizedHandler.class);

  @Autowired
  private WxCompService compService;
  @Autowired
  private WxAppAccountServiceI appAccountService;
  @Autowired
  private WxAccountServiceI wxAccountService;
  @Autowired
  private WxCompConfigStorage compConfig;
  @Autowired
  private SystemService systemService;

  @Override
  public String handle(WxXmlMessage wxMessage, Map<String, Object> context)
      throws WxErrorException {
    if (logger.isDebugEnabled()) {
      logger.debug("开始处理开放平台授权消息");
    }

    // 首先要设置当前开放平台的appId
    WxComponentContext.setAppId(wxMessage.getAppId());

    try {
      // 这里不再保存授权码和过期时间,直接查询通过授权码取得授权凭证
      if (logger.isDebugEnabled()) {
        logger.debug("通过授权码查询授权信息");
      }
      final WxAuthorizationInfo authInfo = compService.getAuthorService()
          .queryAuthor(wxMessage.getAuthorizationCode()).getAuthorizationInfo();

      // 先查询授权人详细信息
      if (logger.isDebugEnabled()) {
        logger.debug("通过授权码查询授权人信息");
      }
      final WxGetAuthorizerInfoResult authorizerInfo = compService.getAuthorService()
          .getAuthorizerInfo(authInfo.getAuthorizerAppid());

      // 如果没有创建小程序或公众号，则自动创建小程序和公众号账户！！！
      if (logger.isDebugEnabled()) {
        logger.debug("创建小程序或公众号账户");
      }
      createAuthorizerAccountIfAbsent(authorizerInfo);

      // 保存授权凭据和接口调用凭据刷新令牌
      if (logger.isDebugEnabled()) {
        logger.debug("保存授权凭据和接口调用凭据刷新令牌");
      }
      compConfig.updateAuthorizerAccessToken(authInfo.getAuthorizerAppid(),
          authInfo.getAuthorizerAccessToken(), authInfo.getExpiresIn(),
          authInfo.getAuthorizerRefreshToken());

      // 预处理授权方账户
      if (logger.isDebugEnabled()) {
        logger.debug("预处理授权方账户");
      }
      preprocessAuthorizerAccount(authorizerInfo);

      if (logger.isInfoEnabled()) {
        logger.info("更新授权凭据成功.");
      }
      // 第三方平台方在收到授权相关通知后也需进行解密（详细请见【消息加解密接入指引】），接收到后之后只需直接返回字符串success。
      return WxConsts.SUCCESS_MSG;
    } catch (Exception e) {
      logger.error("处理授权通知失败", e);
      throw new WxErrorException(-1, e.getMessage());
    }
  }

  /**
   * 如果没有授权方的账户则创建之
   * 
   * @param authorizerInfo
   */
  private void createAuthorizerAccountIfAbsent(WxGetAuthorizerInfoResult authorizerInfo)
      throws Exception {
    if (authorizerInfo.isWxApp()) {
      createAppAccountIfAbsent(authorizerInfo);
    } else if (authorizerInfo.isMp()) {
      createMpAccountIfAbsent(authorizerInfo);
    } else {
      throw new RuntimeException("不能识别的授权方账户类型");
    }
  }

  /**
   * 如果公众号账户不存在则创建之
   * 
   * @param authorizerInfo
   * @throws Exception
   */
  private void createMpAccountIfAbsent(WxGetAuthorizerInfoResult authorizerInfo) throws Exception {
    final me.chanjar.weixin.component.bean.author.WxGetAuthorizerInfoResult.WxAuthorizationInfo authInfo = authorizerInfo
        .getAuthorizationInfo();
    final WxAuthorizerInfo authorizer = authorizerInfo.getAuthorizerInfo();

    WxAccountEntity account = wxAccountService.getAccountByAppId(authInfo.getAuthorizerAppid());
    if (account != null) {
      return;
    }

    account = new WxAccountEntity();
    account.setComponentAppId(WxComponentContext.getAppId());
    account.setAppid(authInfo.getAuthorizerAppid());
    account.setName(authorizer.getNickName());
    account.setOriginalId(authorizer.getUserName());
    if (authorizer.getServiceTypeInfo() != null) {
      int id = authorizer.getServiceTypeInfo().getId();
      if (id == 0 || id == 1) {
        account.setType("1");
      } else if (id == 2) {
        account.setType("2");
      } else {
        account.setType(id + "");
      }
    }
    wxAccountService.save(account);
  }

  /**
   * 如果小程序账户不存在则创建之
   * 
   * @param authorizerInfo
   * @throws Exception
   */

  private void createAppAccountIfAbsent(WxGetAuthorizerInfoResult authorizerInfo) throws Exception {
    final me.chanjar.weixin.component.bean.author.WxGetAuthorizerInfoResult.WxAuthorizationInfo authInfo = authorizerInfo
        .getAuthorizationInfo();
    final WxAuthorizerInfo authorizer = authorizerInfo.getAuthorizerInfo();

    WxAppAccountEntity account = appAccountService.getAccountByAppId(authInfo.getAuthorizerAppid());
    if (account != null) {
      account.setIsHosted(true);// 解决之前手动录入,后来又授权托管却没有更新托管状态
      appAccountService.save(account);
      return;
    }

    String orgCode = null;
    String hql = "from " + TSDepart.class.getName() + " t where t.departname = ?";
    List<TSDepart> tsDeparts = systemService.findByHql(hql,
        authorizerInfo.getAuthorizerInfo().getPrincipalName());

    if (tsDeparts == null || tsDeparts.size() == 0) {
      // 创建用户组织及账户
      orgCode = createOrgAndUserAcct(authorizerInfo.getAuthorizerInfo());

    } else {
      orgCode = tsDeparts.get(0).getOrgCode();
    }

    account = new WxAppAccountEntity();
    account.setSysOrgCode(orgCode);
    account.setDeploymentMethod(DeploymentMethod.THIRD_PALTFORM);
    account.setComponentAppId(WxComponentContext.getAppId());
    account.setAppId(authInfo.getAuthorizerAppid());
    account.setOriginalId(authorizer.getUserName());
    account.setName(authorizer.getNickName());
    account.setParterLogoUrl(authorizer.getHeadImg());
    account.setIsHosted(true);
    appAccountService.save(account);
  }


  public String createOrgAndUserAcct(WxAuthorizerInfo authorizerInfo) throws ServiceException {
    String parentOrgCode = ResourceUtil.getConfigByName("gomore.orgCode");
    String childOrgCode = null;
    TSDepart parentDepart = systemService.findUniqueByProperty(TSDepart.class, "orgCode",
        parentOrgCode);

    if (parentDepart == null) {
      throw new ServiceException("orgCode=" + parentOrgCode + "的组织不存在");
    } else {

      // 创建下级组织
      TSDepart childDepart = new TSDepart();
      childDepart.setTSPDepart(parentDepart);

      childOrgCode = generateOrgCode(parentDepart.getId(), parentOrgCode);
      childDepart.setOrgType("3");
      childDepart.setOrgCode(childOrgCode);
      childDepart.setDepartname(authorizerInfo.getPrincipalName());
      childDepart.setDescription(authorizerInfo.getPrincipalName());
      systemService.saveOrUpdate(childDepart);

      // 创建用户
      TSUser user = new TSUser();
      user.setDepartid(childDepart.getId());
      user.setUserType("mini_program_user");
      user.setStatus(new Short("1"));
      int beginPos = authorizerInfo.getUserName().length() - 6;
      int endPos = authorizerInfo.getUserName().length();
      user.setUserName(authorizerInfo.getUserName().substring(beginPos, endPos));
      user.setPassword(ResourceUtil.getConfigByName("app.user.password"));
      systemService.saveOrUpdate(user);

      // 创建用户组织
      TSUserOrg tsUserOrg = new TSUserOrg();
      tsUserOrg.setTsDepart(childDepart);
      tsUserOrg.setTsUser(user);
      systemService.saveOrUpdate(tsUserOrg);

      // 创建角色
      TSRole tsRole = generateRole();

      // 创建用户角色
      TSRoleUser roleUser = new TSRoleUser();
      roleUser.setTSRole(tsRole);
      roleUser.setTSUser(user);
      systemService.saveOrUpdate(roleUser);
    }
    return childOrgCode;
  }

  // 创建角色
  private TSRole generateRole() {
    String hql = "from " + TSRole.class.getName() + " where roleCode = ?";
    List<TSRole> list = systemService.findByHql(hql, ResourceUtil.getConfigByName("app.roleCode"));

    if (list == null || list.size() == 0) {
      TSRole role = new TSRole();
      role.setRoleCode(ResourceUtil.getConfigByName("app.roleCode"));
      role.setRoleName(ResourceUtil.getConfigByName("app.roleName"));
      systemService.saveOrUpdate(role);
      return role;
    } else {
      return list.get(0);
    }

  }

  // 生成新的组织代码
  private String generateOrgCode(String id, String parentOrgCode) {

    String hql = "select max(orgCode) from " + TSDepart.class.getName() + " where TSPDepart.id = ?";

    List<String> list = systemService.findByHql(hql, id);

    if (list == null || list.size() == 0 || list.get(0) == null) {
      return parentOrgCode + "001";
    } else {
      return String.valueOf(Integer.valueOf(list.get(0)) + 1);
    }
  }

  /**
   * 处理授权方的账户
   * 
   * @param authorizerInfo
   * @throws Exception
   */
  private void preprocessAuthorizerAccount(WxGetAuthorizerInfoResult authorizerInfo)
      throws Exception {
    final String authorizerAppId = authorizerInfo.getAuthorizationInfo().getAuthorizerAppid();
    WxAppContext.setAppId(authorizerAppId);

    // 设置小程序账户的安全域名
    if (authorizerInfo.isWxApp()) {
      logger.debug("正在更新小程序账户的安全域名");

      String domain = compConfig.getDomain();
      WxAppDomains domains = new WxAppDomains();
      domains.addDownloadDomains("https://" + domain);
      domains.addRequestDomains("https://" + domain);
      domains.addUploadDomains("https://" + domain);
      domains.addWsrequestDomains("wss://" + domain);

      try {
        compService.getMaServiceDelegate().getMaDomainService().addDomain(domains);
      } catch (WxErrorException e) {
        // 两次添加的错误码是 85017
        if (e.getError().getErrorCode() != 85017) {
          throw e;
        }
      }
    } else if (authorizerInfo.isMp()) {
    } else {
    }
  }

}
